/*
 * Copyright (C) 2005-2011 MaNGOS <http://www.getmangos.com/>
 *
 * Copyright (C) 2008-2011 Trinity <http://www.trinitycore.org/>
 *
 * Copyright (C) 2006-2011 ScriptDev2 <http://www.scriptdev2.com/>
 *
 * Copyright (C) 2010-2011 ProjectSkyfire <http://www.projectskyfire.org/>
 * 
 * Copyright (C) 2011 ArkCORE <http://www.arkania.net/>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */

/* ScriptData
 SDName: Instance_Dark_Portal
 SD%Complete: 50
 SDComment: Quest support: 9836, 10297. Currently in progress.
 SDCategory: Caverns of Time, The Dark Portal
 EndScriptData */

#include "ScriptPCH.h"
#include "dark_portal.h"

#define MAX_ENCOUNTER              2

#define C_MEDIVH                15608
#define C_TIME_RIFT             17838

#define SPELL_RIFT_CHANNEL      31387

#define RIFT_BOSS               1

inline uint32 RandRiftBoss() {
	return ((rand() % 2) ? C_RKEEP : C_RLORD);
}

float PortalLocation[4][4] = { { -2041.06f, 7042.08f, 29.99f, 1.30f }, {
		-1968.18f, 7042.11f, 21.93f, 2.12f }, { -1885.82f, 7107.36f, 22.32f,
		3.07f }, { -1928.11f, 7175.95f, 22.11f, 3.44f } };

struct Wave {
	uint32 PortalBoss; //protector of current portal
	uint32 NextPortalTime; //time to next portal, or 0 if portal boss need to be killed
};

static Wave RiftWaves[] = { { RIFT_BOSS, 0 }, { C_DEJA, 0 },
		{ RIFT_BOSS, 120000 }, { C_TEMPO, 140000 }, { RIFT_BOSS, 120000 }, {
				C_AEONUS, 0 } };

class instance_dark_portal: public InstanceMapScript {
public:
	instance_dark_portal() :
			InstanceMapScript("instance_dark_portal", 269) {
	}

	InstanceScript* GetInstanceScript(InstanceMap* pMap) const {
		return new instance_dark_portal_InstanceMapScript(pMap);
	}

	struct instance_dark_portal_InstanceMapScript: public InstanceScript {
		instance_dark_portal_InstanceMapScript(Map* pMap) :
				InstanceScript(pMap) {
			Initialize();
		}
		;

		uint32 m_auiEncounter[MAX_ENCOUNTER];

		uint32 mRiftPortalCount;
		uint32 mShieldPercent;
		uint8 mRiftWaveCount;
		uint8 mRiftWaveId;

		uint32 NextPortal_Timer;

		uint64 MedivhGUID;
		uint8 CurrentRiftId;

		void Initialize() {
			MedivhGUID = 0;
			Clear();
		}

		void Clear() {
			memset(&m_auiEncounter, 0, sizeof(m_auiEncounter));

			mRiftPortalCount = 0;
			mShieldPercent = 100;
			mRiftWaveCount = 0;
			mRiftWaveId = 0;

			CurrentRiftId = 0;

			NextPortal_Timer = 0;
		}

		void InitWorldState(bool Enable = true) {
			DoUpdateWorldState(WORLD_STATE_BM, Enable ? 1 : 0);
			DoUpdateWorldState(WORLD_STATE_BM_SHIELD, 100);
			DoUpdateWorldState(WORLD_STATE_BM_RIFT, 0);
		}

		bool IsEncounterInProgress() {
			if (GetData(TYPE_MEDIVH) == IN_PROGRESS)
				return true;

			return false;
		}

		void OnPlayerEnter(Player* pPlayer) {
			if (GetData(TYPE_MEDIVH) == IN_PROGRESS)
				return;

			pPlayer->SendUpdateWorldState(WORLD_STATE_BM, 0);
		}

		void OnCreatureCreate(Creature* pCreature, bool /*add*/) {
			if (pCreature->GetEntry() == C_MEDIVH)
				MedivhGUID = pCreature->GetGUID();
		}

		//what other conditions to check?
		bool CanProgressEvent() {
			if (instance->GetPlayers().isEmpty())
				return false;

			return true;
		}

		uint8 GetRiftWaveId() {
			switch (mRiftPortalCount) {
			case 6:
				mRiftWaveId = 2;
				return 1;
			case 12:
				mRiftWaveId = 4;
				return 3;
			case 18:
				return 5;
			default:
				return mRiftWaveId;
			}
		}

		void SetData(uint32 type, uint32 data) {
			switch (type) {
			case TYPE_MEDIVH:
				if (data == SPECIAL && m_auiEncounter[0] == IN_PROGRESS) {
					--mShieldPercent;

					DoUpdateWorldState(WORLD_STATE_BM_SHIELD, mShieldPercent);

					if (!mShieldPercent) {
						if (Creature* pMedivh = instance->GetCreature(MedivhGUID)) {
							if (pMedivh->isAlive()) {
								pMedivh->DealDamage(pMedivh,
										pMedivh->GetHealth(), NULL,
										DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL,
										NULL, false);
								m_auiEncounter[0] = FAIL;
								m_auiEncounter[1] = NOT_STARTED;
							}
						}
					}
				} else {
					if (data == IN_PROGRESS) {
						sLog->outDebug(LOG_FILTER_TSCR,
								"TSCR: Instance Dark Portal: Starting event.");
						InitWorldState();
						m_auiEncounter[1] = IN_PROGRESS;
						NextPortal_Timer = 15000;
					}

					if (data == DONE) {
						//this may be completed further out in the post-event
						sLog->outDebug(LOG_FILTER_TSCR,
								"TSCR: Instance Dark Portal: Event completed.");
						Map::PlayerList const& players = instance->GetPlayers();

						if (!players.isEmpty()) {
							for (Map::PlayerList::const_iterator itr =
									players.begin(); itr != players.end();
									++itr) {
								if (Player* pPlayer = itr->getSource()) {
									if (pPlayer->GetQuestStatus(
											QUEST_OPENING_PORTAL)
											== QUEST_STATUS_INCOMPLETE)
										pPlayer->AreaExploredOrEventHappens(
												QUEST_OPENING_PORTAL);

									if (pPlayer->GetQuestStatus(
											QUEST_MASTER_TOUCH)
											== QUEST_STATUS_INCOMPLETE)
										pPlayer->AreaExploredOrEventHappens(
												QUEST_MASTER_TOUCH);
								}
							}
						}
					}

					m_auiEncounter[0] = data;
				}
				break;
			case TYPE_RIFT:
				if (data == SPECIAL) {
					if (mRiftPortalCount < 7)
						NextPortal_Timer = 5000;
				} else
					m_auiEncounter[1] = data;
				break;
			}
		}

		uint32 GetData(uint32 type) {
			switch (type) {
			case TYPE_MEDIVH:
				return m_auiEncounter[0];
			case TYPE_RIFT:
				return m_auiEncounter[1];
			case DATA_PORTAL_COUNT:
				return mRiftPortalCount;
			case DATA_SHIELD:
				return mShieldPercent;
			}
			return 0;
		}

		uint64 GetData64(uint32 data) {
			if (data == DATA_MEDIVH)
				return MedivhGUID;

			return 0;
		}

		Creature* SummonedPortalBoss(Creature* me) {
			uint32 entry = RiftWaves[GetRiftWaveId()].PortalBoss;

			if (entry == RIFT_BOSS)
				entry = RandRiftBoss();

			sLog->outDebug(LOG_FILTER_TSCR,
					"TSCR: Instance Dark Portal: Summoning rift boss entry %u.",
					entry);

			Position pos;
			me->GetRandomNearPosition(pos, 10.0f);

			//normalize Z-level if we can, if rift is not at ground level.
			pos.m_positionZ = std::max(
					me->GetMap()->GetHeight(pos.m_positionX, pos.m_positionY,
							MAX_HEIGHT),
					me->GetMap()->GetWaterLevel(pos.m_positionX,
							pos.m_positionY));

			if (Creature *summon = me->SummonCreature(entry, pos, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 600000))
				return summon;

			sLog->outDebug(
					LOG_FILTER_TSCR,
					"TSCR: Instance Dark Portal: What just happened there? No boss, no loot, no fun...");
			return NULL;
		}

		void DoSpawnPortal() {
			if (Creature* pMedivh = instance->GetCreature(MedivhGUID)) {
				uint8 tmp = urand(0, 2);

				if (tmp >= CurrentRiftId)
					++tmp;

				sLog->outDebug(
						LOG_FILTER_TSCR,
						"TSCR: Instance Dark Portal: Creating Time Rift at locationId %i (old locationId was %u).",
						tmp, CurrentRiftId);

				CurrentRiftId = tmp;

				Creature *pTemp = pMedivh->SummonCreature(C_TIME_RIFT,
						PortalLocation[tmp][0], PortalLocation[tmp][1],
						PortalLocation[tmp][2], PortalLocation[tmp][3],
						TEMPSUMMON_CORPSE_DESPAWN, 0);
				if (pTemp) {
					pTemp->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
					pTemp->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);

					if (Creature *pBoss = SummonedPortalBoss(pTemp)) {
						if (pBoss->GetEntry() == C_AEONUS)
							pBoss->AddThreat(pMedivh, 0.0f);
						else {
							pBoss->AddThreat(pTemp, 0.0f);
							pTemp->CastSpell(pBoss, SPELL_RIFT_CHANNEL, false);
						}
					}
				}
			}
		}

		void Update(uint32 diff) {
			if (m_auiEncounter[1] != IN_PROGRESS)
				return;

			//add delay timer?
			if (!CanProgressEvent()) {
				Clear();
				return;
			}

			if (NextPortal_Timer) {
				if (NextPortal_Timer <= diff) {
					++mRiftPortalCount;

					DoUpdateWorldState(WORLD_STATE_BM_RIFT, mRiftPortalCount);

					DoSpawnPortal();
					NextPortal_Timer =
							RiftWaves[GetRiftWaveId()].NextPortalTime;
				} else
					NextPortal_Timer -= diff;
			}
		}
	};
};

void AddSC_instance_dark_portal() {
	new instance_dark_portal();
}
